package cn.emailChat.ai.consumer;

import cn.emailChat.ai.consumer.util.PromptComposer;
import cn.emailChat.ai.dto.MailInboundEvent;
import cn.emailChat.ai.dto.MemoryContext;
import cn.emailChat.ai.replychain.ReplyHandler;

import cn.emailChat.ai.common.enums.MessageStatusType;
import cn.emailChat.ai.domain.Email;
import cn.emailChat.ai.domain.MessageStatus;
import cn.emailChat.ai.repo.EmailRepo;
import cn.emailChat.ai.repo.MessageStatusRepo;

import cn.emailChat.ai.consumer.util.SmtpSender;
import cn.emailChat.ai.service.MemoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Optional;

@Service
@Slf4j
public class AutoReplyConsumer {

    private final MemoryService memoryService;
    private final SmtpSender smtpSender;
    private final ReplyHandler replyChainHead; // 责任链链头
    private final MessageStatusRepo messageStatusRepo;
    private final EmailRepo emailRepo;

    @Value("${spring.mail.username}")
    private String fromAddress;

    // ⚠️ 改为注入交换机名称（方案B：分区队列）
    @Value("${mail.reply.exchange:auto.reply.x}")
    private String replyExchangeName;

    public AutoReplyConsumer(MemoryService memoryService, SmtpSender smtpSender, ReplyHandler replyChainHead,
                             MessageStatusRepo messageStatusRepo,
                             EmailRepo emailRepo) {
        this.memoryService = memoryService;
        this.smtpSender = smtpSender;
        this.replyChainHead = replyChainHead;
        this.messageStatusRepo = messageStatusRepo;
        this.emailRepo = emailRepo;
    }

    // 每个分区队列一个监听方法（容器并发=1）
    @RabbitListener(queues = "auto.reply.q.p0")
    public void consumeP0(MailInboundEvent e, org.springframework.amqp.core.Message amqpMessage) {
        String consumerQueue = amqpMessage.getMessageProperties().getConsumerQueue();
        onMailIncoming(e, consumerQueue);
    }

    @RabbitListener(queues = "auto.reply.q.p1")
    public void consumeP1(MailInboundEvent e, org.springframework.amqp.core.Message amqpMessage) {
        String consumerQueue = amqpMessage.getMessageProperties().getConsumerQueue();
        onMailIncoming(e, consumerQueue);
    }

    @RabbitListener(queues = "auto.reply.q.p2")
    public void consumeP2(MailInboundEvent e, org.springframework.amqp.core.Message amqpMessage) {
        String consumerQueue = amqpMessage.getMessageProperties().getConsumerQueue();
        onMailIncoming(e, consumerQueue);
    }

    @Transactional
    public void onMailIncoming(MailInboundEvent event, String consumerQueue) {
        LocalDateTime now = LocalDateTime.now();

        // 1) 预更新消息状态为 SENDING（记录交换机名；队列名打印到日志便于排查）
        MessageStatus status = upsertStatusToSending(event.getMessageId(), now);
        log.info("[AutoReplyConsumer] 接收到分区消息: msgId={}, queue={}, from={}",
                event.getMessageId(), consumerQueue, event.getFromEmail());

        String replySubject = null;
        String replyText = null;
        boolean replyPreExisted = false;     // 标记：是否已存在回复（则不再保存）
        String replyMsgId = event.getMessageId() + "_reply";

        try {
            if (event.getFromEmail() == null || event.getFromEmail().trim().isEmpty()) {
                log.warn("[AutoReplyConsumer] 缺少发件邮箱，跳过: {}", event);
                markStatusFailed(status, now, "缺少发件邮箱");
                return;
            }

            // 先查数据库里是否已有对应的回复（表示之前已生成过）
            Optional<Email> replyOpt = emailRepo.findByMessageId(replyMsgId);
            if (replyOpt.isPresent()) {
                // ✅ 已有回复内容：直接使用，跳过 AI 生成
                Email reply = replyOpt.get();
                replySubject = reply.getSubject();
                replyText = reply.getBody();
                replyPreExisted = true;

                if (replySubject == null || replyText == null) {
                    // 极端兜底：若库里内容不完整，则仍按旧流程生成
                    log.warn("[AutoReplyConsumer] 发现已有回复记录但内容不完整，改为重新生成: msgId={}", replyMsgId);
                    replyPreExisted = false;
                }
            }

            if (!replyPreExisted) {
                // ====== 在“构建回复内容”之前接入记忆 ======
                String threadId = memoryService.locateThreadId(event);
                MemoryContext ctx = memoryService.buildContext(threadId, event);
                // 构建回复内容（可能抛异常，因此放在 try 内）
                replySubject = buildReplySubject(event.getSubject());
                replyText = buildReplyBody(event, ctx);
            }

            // 2) 发送邮件（无论是复用内容还是新生成内容）
            smtpSender.sendText(fromAddress, event.getFromEmail(), replySubject, replyText);
            log.info("[AutoReplyConsumer] 已自动回复至: {} | queue={}", event.getFromEmail(), consumerQueue);

            // 3) 成功：更新邮件表 processed=true；消息状态为 ACKED
            markEmailProcessed(event.getMessageId());
            markStatusAcked(status, now);

        } catch (Exception e) {
            log.error("[AutoReplyConsumer] 自动回复失败: {} | event={}", e.getMessage(), event, e);
            markStatusFailed(status, now, e.getMessage());
            // 不 return，交由 finally 做“尝试保存回复记录”（仅当为新生成的场景）
        } finally {
            // 4) 保存发出邮件回复：
            //    只有在“本次是新生成的回复”时才保存；如果是复用已有回复（replyPreExisted=true），就不重复保存。
            if (!replyPreExisted && replySubject != null && replyText != null) {
                try {
                    saveReplyEmail(replyMsgId, replySubject, replyText, now);
                } catch (Exception saveEx) {
                    log.error("[AutoReplyConsumer] 保存回复邮件记录失败: msgId={}, err={}",
                            replyMsgId, saveEx.getMessage(), saveEx);
                }
            } else if (replyPreExisted) {
                // 可选：更新该已存在回复的再次发送时间（不强制）
                try {
                    emailRepo.findByMessageId(replyMsgId).ifPresent(r -> {
                        r.setSendTime(now);
                        emailRepo.save(r);
                    });
                } catch (Exception ignore) {
                    log.debug("[AutoReplyConsumer] 更新已存在回复发送时间失败（忽略）: {}", ignore.getMessage());
                }
            } else {
                log.debug("[AutoReplyConsumer] 未生成回复内容，跳过保存: msgId={}", event.getMessageId());
            }
        }
    }



    private String buildReplySubject(String originalSubject) {
        String s = (originalSubject == null || originalSubject.trim().isEmpty()) ? "" : originalSubject.trim();
        if (s.regionMatches(true, 0, "Re:", 0, 3)) return s;
        return "Re: " + s;
    }

    private String buildReplyBody(MailInboundEvent e, MemoryContext ctx){
        final String originalText = e.getPlainText();
        final String composed = PromptComposer.compose(ctx, e.getSubject(), originalText);

        MailInboundEvent enriched = new MailInboundEvent(
                e.getMessageId(), e.getSubject(), e.getFromEmail(),
                e.getToEmail(), e.getReceivedDate(), /* plainText= */ composed
                // 若还有其它字段，按你的 DTO 构造器一并传入
        );

        String aiAnswer = replyChainHead.handle(enriched);

        try {
            memoryService.updateAfterReply(
                    ctx.getThreadId(), e.getFromEmail(), e.getSubject(),
                    e.getMessageId(), originalText, aiAnswer);
        } catch (Exception memEx) {
            log.warn("[buildReplyBody] 更新记忆失败（忽略）: {}", memEx.getMessage(), memEx);
        }

        return aiAnswer + "\n\n"
                + "------ 原始来信摘要 ------\n"
                + "发件人: " + e.getFromEmail() + "\n"
                + "主题: " + (e.getSubject() == null ? "" : e.getSubject()) + "\n"
                + "内容节选: " + snippet(originalText, 200) + "\n";
    }

    private String snippet(String s, int maxLen) {
        if (s == null) return "";
        s = s.replaceAll("\\s+", " ").trim();
        return s.length() <= maxLen ? s : s.substring(0, maxLen) + "...";
    }

    /* ---------------------- 状态流转与持久化辅助方法 ---------------------- */

    private MessageStatus upsertStatusToSending(String messageId, LocalDateTime now) {
        MessageStatus status = messageStatusRepo.findByMessageId(messageId)
                .orElseGet(MessageStatus::new);

        status.setMessageId(messageId);
        // ✅ 这里改为记录交换机名（方案B）
        status.setExchangeName(replyExchangeName);
        status.setStatus(MessageStatusType.SENT); // 或 PROCESSING（按你的枚举）
        if (status.getRetryCount() == null) status.setRetryCount(0);
        if (status.getCreateTime() == null) status.setCreateTime(now);
        status.setUpdateTime(now);
        return messageStatusRepo.save(status);
    }

    private void markStatusAcked(MessageStatus status, LocalDateTime now) {
        status.setStatus(MessageStatusType.CONFIRMED);
        status.setUpdateTime(now);
        messageStatusRepo.save(status);
    }

    private void markStatusFailed(MessageStatus status, LocalDateTime now, String reason) {
        status.setStatus(MessageStatusType.FAILED);
        status.setRetryCount(status.getRetryCount() == null ? 0 : status.getRetryCount()); //此处不再增加重试次数，而是统一在retry定时任务中增加
        status.setUpdateTime(now);
        messageStatusRepo.save(status);
    }

    private void markEmailProcessed(String messageId) {
        Optional<Email> opt = emailRepo.findByMessageId(messageId);
        if (opt.isPresent()) {
            Email email = opt.get();
            if (email.getProcessed() == null || !email.getProcessed()) {
                email.setProcessed(true);
                emailRepo.save(email);
            }
        } else {
            Email fallback = new Email();
            fallback.setMessageId(messageId);
            fallback.setProcessed(true);
            emailRepo.save(fallback);
        }
    }

    /** 保存系统发出的自动回复到 Email 表 */
    private void saveReplyEmail(String originalMessageId, String subject, String body, LocalDateTime sendTime) {
        Email replyEmail = new Email();
        replyEmail.setMessageId(originalMessageId + "_reply");
        replyEmail.setFromEmail(fromAddress);
        replyEmail.setSubject(subject);
        replyEmail.setBody(body);
        replyEmail.setSendTime(sendTime);
        replyEmail.setProcessed(true);
        emailRepo.save(replyEmail);

        log.info("[AutoReplyConsumer] 回复邮件已存储到 Email 表, messageId={}, from={}",
                replyEmail.getMessageId(), replyEmail.getFromEmail());
    }
}
